
#define MATH_MACRO_VcdotV(vec_1, vec_2) ((vec_1)[X]*(vec_2)[X] + (vec_1)[Y]*(vec_2)[Y] + (vec_1)[Z]*(vec_2)[Z])
#define MATH_MACRO_VxV(vec_1, vec_2) Vector<T,K>((vec_1)[Y]*(vec_2)[Z] - (vec_1)[Z]*(vec_2)[Y], \
                                     (vec_1)[Z]*(vec_2)[X] - (vec_1)[X]*(vec_2)[Z], \
                                     (vec_1)[X]*(vec_2)[Y] - (vec_1)[Y]*(vec_2)[X], 0) 


namespace Math
{


    
template <typename T, typename K>
T OWVector<T,K>::VcdotV(const Vector<T,K>& vec_1, const Vector<T,K>& vec_2)
  {
      return MATH_MACRO_VcdotV(vec_1, vec_2);
  }



template <typename T, typename K>
Vector<T,K> OWVector<T,K>::VxV(const Vector<T,K>& vec_1, const Vector<T,K>& vec_2)
  {
      return  MATH_MACRO_VxV(vec_1, vec_2);                                 
  }


//********************************************************************************************************************


template <typename T, typename K>
T OWVector<T,K>::VcdotV(const Vector<T,K>* const vec_1, const Vector<T,K>* const vec_2)
  {
      return MATH_MACRO_VcdotV(*vec_1, *vec_2);
  }





template <typename T, typename K>
Vector<T,K>* OWVector<T,K>::VxV(const Vector<T,K>* const vec_1, const Vector<T,K>* const vec_2)
  {
      return MATH_MACRO_VxV(*vec_1, *vec_2);
  }



//*********************************************************************************************************************



template <typename T, typename K>
T OWVector<T,K>::VcdotV(const Vector<T,K>& vec_1, const T* const vec_2)
  {
      return MATH_MACRO_VcdotV(vec_1, vec_2);
  }



template <typename T, typename K>  
Vector<T,K> OWVector<T,K>::VxV(const Vector<T,K>& vec_1, const T* const vec_2)
  {
      return MATH_MACRO_VxV(vec_1, vec_2);
  }


template <typename T, typename K>
Vector<T,K> OWVector<T,K>::VxV(const T* const vec_1, const Vector<T,K>& vec_2)
  {
      return MATH_MACRO_VxV(vec_1, vec_2);
  }



//*********************************************************************************************************************


template <typename T, typename K>
T OWVector<T,K>::VcdotV(const Vector<T,K>* const vec_1, const T* const vec_2)
  {
      return MATH_MACRO_VcdotV(*vec_1, vec_2);
  }



template <typename T, typename K>
Vector<T,K>* OWVector<T,K>::VxV(const Vector<T,K>* const vec_1, const T* const vec_2)
  {
      return MATH_MACRO_VxV(*vec_1, vec_2);
  }



template <typename T, typename K>
Vector<T,K>* OWVector<T,K>::VxV(const T* const vec_1, const Vector<T,K>* const vec_2)
  {
      return MATH_MACRO_VxV(vec_1, *vec_2);
  }



//**********************************************************************************************************************



template <typename T, typename K>  
Vector<T,K> OWVector<T,K>::LinearCombination(Vector<T,K>** vec_array, const Vector<T,K>& coordinates)
  {
      Vector<T,K> help_vector;

       help_vector = (coordinates[X]) * (*vec_array[X]) + (coordinates[Y]) * (*vec_array[Y]) +
                     (coordinates[Z]) * (*vec_array[Z]) + (coordinates[W]) * (*vec_array[W]);

       return help_vector;
  }



template <typename T, typename K>
Vector<T,K>* OWVector<T,K>::LinearCombination(Vector<T,K>** vec_array, const Vector<T,K>* const coordinates)
  {
      Vector<T,K>* help_vector = new Vector<T,K>();;

      (*help_vector) = (*coordinates)[X] * (*vec_array[X]) + (*coordinates)[Y] * (*vec_array[Y]) +
                       (*coordinates)[Z] * (*vec_array[Z]) + (*coordinates)[W] * (*vec_array[W]);

      return help_vector;
  }


} // end namespace math
